package com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.impl;

import com.derbysoft.dswitch.adapter.ihg.common.domain.*;
import com.derbysoft.dswitch.adapter.ihg.common.domain.RatePlan;
import com.derbysoft.dswitch.adapter.ihg.common.repository.ChannelAuthorizationRepository;
import com.derbysoft.dswitch.adapter.ihg.common.repository.ConfigRepository;
import com.derbysoft.dswitch.adapter.ihg.common.repository.HotelRepository;
import com.derbysoft.dswitch.adapter.ihg.common.repository.RatePlanRepository;
import com.derbysoft.dswitch.adapter.ihg.common.utils.CollectionUtil;
import com.derbysoft.dswitch.adapter.ihg.common.utils.DateTimeUtils;
import com.derbysoft.dswitch.adapter.ihg.dswitch3.translate.Translator;
import com.derbysoft.dswitch.adapter.ihg.dto.*;
import com.derbysoft.dswitch.adapter.ihg.exception.ChannelNotFoundException;
import com.derbysoft.dswitch.adapter.ihg.exception.ConfigItemNotFoundException;
import com.derbysoft.dswitch.adapter.ihg.exception.HotelNotFoundException;
import com.derbysoft.dswitch.dto.common.KeyValue;
import com.derbysoft.dswitch.dto.common.TPAExtensionsDTO;
import com.derbysoft.dswitch.dto.hotel.avail.*;
import com.derbysoft.dswitch.dto.hotel.common.*;
import com.derbysoft.dswitch.dto.hotel.reservation.HotelReservationRS;
import com.derbysoft.dswitch.dto.hotel.reservation.ReservationRoomStayDTO;
import com.derbysoft.dswitch.remote.hotel.dto.AbstractRQ;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailRequest;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailResponse;
import com.derbysoft.dswitch.remote.hotel.dto.HotelReservationRequest;
import com.derbysoft.remote.dswitch.hotel.constants.FreeMealType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * Created by: jason
 * Date: 2012-5-9
 */
public abstract class BaseTranslator {

    public static final int ADULT_QUALITY_CODE = 10;
    public static final int CHILD_QUALITY_CODE = 8;
    public static final String BLANK = "";
    public static final String IHG_TAX_INFORMATION = "Tax Information";
    public static final String IHG_SERVICE_CHARGE_INFORMATION = "Service Charge Information";
    public static final String ROOM_TYPE_NAME_FIELD = "room_type_name_field";
    public static final String ADDITIONAL_DETAIL_CODE = "additional_detail_code";
    public static final String ROOM_RATE_DESCRIPTION = "ROOM_RATE_DESCRIPTION";
    private static final String BED_TYPE_CODE = "BedTypeCode";
    private static final String AND = "&";
    public static final String NO_AVAIL_TEXT = "No availability for this hotel";
    public static final int ONE_HUNDRED = 100;


    private final Log logger = LogFactory.getLog(BaseTranslator.class);

    @Autowired
    protected HotelRepository hotelRepository;

    @Autowired
    protected ChannelAuthorizationRepository channelAuthorizationRepository;

    @Autowired
    protected RatePlanRepository ratePlanRepository;

    @Autowired
    protected ConfigRepository configRepository;

    @Value("${dswitch2.adapter}")
    protected String adapter;

    @Value("${provider}")
    protected String provider;


    protected ChannelAuthorization loadChannel(String channelPassport) {
        ChannelAuthorization authorization = channelAuthorizationRepository.loadByDerbyChannelCode(channelPassport);
        if (authorization == null) {
            throw new ChannelNotFoundException(channelPassport);
        }
        return authorization;
    }

    protected ConfigInfo loadConfigInfo(String name) {
        ConfigInfo configInfo = configRepository.loadUsable(name);
        if (configInfo == null) {
            throw new ConfigItemNotFoundException(name);
        }
        return configInfo;
    }

    protected void setRequestAttributes(Request otaRequest, AbstractRQ derbyRequest) {
        otaRequest.setPOS(createPOS(derbyRequest.getHeader().getSource()));
        otaRequest.setVersion(Translator.VERSION);
    }

    protected HotelMapping loadHotel(String providerCode) {
        HotelMapping hotelMapping = hotelRepository.loadByHotelCode(providerCode,HotelStatus.ENABLED);
        if (hotelMapping == null) {
            throw new HotelNotFoundException(providerCode);
        }
        return hotelMapping;
    }

    private POS createPOS(String sourceCode) {
        POS pos = new POS();
        Source source = new Source();
        RequestorId requestorID = new RequestorId();
        requestorID.setID(loadByDerbyCode(sourceCode).getIataNumber());
        requestorID.setType(Translator.REQUEST_TYPE);
        source.setRequestorID(requestorID);
        pos.setSource(source);
        return pos;
    }

    protected ChannelAuthorization loadByDerbyCode(String channelPassport) {
        ChannelAuthorization channel = channelAuthorizationRepository.loadByDerbyChannelCode(channelPassport);
        if (channel == null) {
            throw new ChannelNotFoundException(channelPassport);
        }
        return channel;
    }


    protected void setRateInfo(HotelReservationRS reservationRS, HotelAvailResponse availResponse, HotelReservationRequest reservationRequest) {
        ReservationRoomStayDTO reservationRoomStayDTO = reservationRS.getHotelReservation().getRoomStaysList().get(0);
        final AvailRoomStayDTO availRoomStayDTO = findAvailRoomStay(availResponse, reservationRequest);
        reservationRoomStayDTO.setRoomRate(availRoomStayDTO.getRoomRate());
        reservationRoomStayDTO.setTotal(calcTotal(availRoomStayDTO));
    }

    private TotalDTO calcTotal(AvailRoomStayDTO availRoomStayDTO) {
        TotalDTO totalDTO = new TotalDTO();
        totalDTO.setTaxesList(availRoomStayDTO.getRatePlan().getTaxesList());
        totalDTO.setCurrency(availRoomStayDTO.getCurrency());
        totalDTO.setServiceChargesList(availRoomStayDTO.getRatePlan().getServiceChargesList());
        totalDTO.setAmountBeforeTax(calcAmountBeforeTax(availRoomStayDTO));
        Double amountAfterTax = calcAmountAfterTax(availRoomStayDTO);
        if (amountAfterTax != null) {
            totalDTO.setAmountAfterTax(amountAfterTax);
        }
        return totalDTO;
    }

    private Double calcAmountBeforeTax(AvailRoomStayDTO availRoomStayDTO) {
        BigDecimal amount = BigDecimal.ZERO;
        for (RateDTO rateDTO : availRoomStayDTO.getRoomRate().getRatesList()) {
            int lengthOfStay = DateTimeUtils.getLengthOfStay(rateDTO.getDateRange().getStart(), rateDTO.getDateRange().getEnd()) + 1;
            amount = amount.add(BigDecimal.valueOf(rateDTO.getAmountBeforeTax()).multiply(BigDecimal.valueOf(lengthOfStay)));
        }
        return amount.doubleValue();
    }

    private Double calcAmountAfterTax(AvailRoomStayDTO availRoomStayDTO) {
        BigDecimal amount = BigDecimal.ZERO;
        for (RateDTO rateDTO : availRoomStayDTO.getRoomRate().getRatesList()) {
            if (rateDTO.getAmountAfterTax() == null) {
                return null;
            }
            int lengthOfStay = DateTimeUtils.getLengthOfStay(rateDTO.getDateRange().getStart(), rateDTO.getDateRange().getEnd()) + 1;
            amount = amount.add(BigDecimal.valueOf(rateDTO.getAmountAfterTax()).multiply(BigDecimal.valueOf(lengthOfStay)));
        }
        return amount.doubleValue();
    }

    protected CancelPolicyDTO findCancelPolicy(HotelAvailResponse availResponse, HotelReservationRequest reservationRequest) {
        AvailRoomStayDTO availRoomStay = findAvailRoomStay(availResponse, reservationRequest);
        return availRoomStay != null ? availRoomStay.getRatePlan().getCancelPolicy() : null;
    }

    private AvailRoomStayDTO findAvailRoomStay(HotelAvailResponse availResponse, HotelReservationRequest reservationRequest) {
        ReservationRoomStayDTO reservationRoomStayDTO = reservationRequest.getHotelReservationRQ()
                .getHotelReservation().getRoomStaysList().get(0);
        HotelAvailRoomStayDTO availRoomStayDTO = availResponse.getHotelAvailRS().getHotelAvailRoomStaysList().get(0);
        for (AvailRoomStayDTO roomStayDTO : availRoomStayDTO.getRoomStaysList()) {
            if (roomStayDTO.getRatePlan().getCode().equals(reservationRoomStayDTO.getRatePlanCode())
                    || roomStayDTO.getRoomType().getCode().equals(reservationRoomStayDTO.getRoomTypeCode())) {
                return roomStayDTO;
            }
        }
        return null;
    }

    protected List<AvailRoomStayDTO> createRoomStays(OTAHotelAvailRS otaHotelAvailRS, HotelAvailRequest request) {
        return new ArrayList<AvailRoomStayDTO>(createAvailRoomStayDTOsMap(otaHotelAvailRS, request).values());
    }

    private Map<String, AvailRoomStayDTO> createAvailRoomStayDTOsMap(OTAHotelAvailRS otaHotelAvailRS, HotelAvailRequest request) {
        Map<String, AvailRoomStayDTO> availRoomStayDTOHashMap = new HashMap<String, AvailRoomStayDTO>();
        if (CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay())
                || otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate())
                || otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate().get(0).getRates() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate().get(0).getRates().getRate())) {
            return availRoomStayDTOHashMap;
        }
        for (RoomRate roomRate : otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomRates().getRoomRate()) {
            RatePlan ratePlanMapping = ratePlanRepository.loadByCode(roomRate.getRatePlanCode());
            if (ratePlanMapping == null) {
                continue;
            }
            RoomType roomType = findRoomType(roomRate.getRoomTypeCode(), otaHotelAvailRS);
            RatePlanDTO ratePlanDTO = createRatePlanDTO(ratePlanMapping, roomRate, request);
            RoomTypeDTO roomTypeDTO = translateRoomType(roomType, roomRate);
            RoomRateDTO roomRateDTO = translateRoomRate(roomRate, otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getTimeSpan());
            AvailRoomStayDTO availRoomStayDTO = new AvailRoomStayDTO();
            availRoomStayDTO.setCurrency(roomRate.getRates().getRate().get(0).getBase().getCurrencyCode());
            availRoomStayDTO.setLanguage(Translator.LANGUAGE);
            availRoomStayDTO.setQuantity(roomType.getNumberOfUnits());
            availRoomStayDTO.setRatePlan(ratePlanDTO);
            availRoomStayDTO.setRoomType(roomTypeDTO);
            availRoomStayDTO.setRoomRate(roomRateDTO);

            availRoomStayDTOHashMap.put(roomRate.getRoomTypeCode(), availRoomStayDTO);
        }
        return availRoomStayDTOHashMap;
    }

    public RoomRateDTO translateRoomRate(RoomRate roomRate, TimeSpan timeSpan) {
        RoomRateDTO roomRateDTO = new RoomRateDTO();
        roomRateDTO.setRatesList(IhgRates2RateDTOsTranslator.translate(roomRate.getRates().getRate(), timeSpan));
        if (roomRate.getRoomRateDescription() != null) {
            roomRateDTO.setDescription(roomRate.getRoomRateDescription().getURL());
        }
        return roomRateDTO;
    }

    protected RoomType findRoomType(String roomTypeCode, OTAHotelAvailRS otaHotelAvailRS) {
        if (otaHotelAvailRS.getRoomStays() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay())
                || otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomTypes() == null
                || CollectionUtils.isEmpty(otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomTypes().getRoomType())) {
            return null;
        }
        for (RoomType roomType : otaHotelAvailRS.getRoomStays().getRoomStay().get(0).getRoomTypes().getRoomType()) {
            if (roomTypeCode.equals(roomType.getRoomTypeCode())) {
                return roomType;
            }
        }
        return null;
    }

    private RatePlanDTO createRatePlanDTO(RatePlan ratePlanMapping, RoomRate roomRate, HotelAvailRequest request) {
        String start = request.getHotelAvailRQ().getAvailCriteria().getStayDateRange().getCheckin();
        String end = DateTimeUtils.formatDate(DateTimeUtils.addDays(DateTimeUtils.parse(
                request.getHotelAvailRQ().getAvailCriteria().getStayDateRange().getCheckout()), -1));

        RatePlanDTO ratePlanDTO = new RatePlanDTO();
        ratePlanDTO.setName(ratePlanMapping.getName());
        ratePlanDTO.setPaymentType(translatePaymentType(ratePlanMapping.getPaymentType()));
        ratePlanDTO.setCode(ratePlanMapping.getCode());
        ratePlanDTO.setTaxesList(translateTaxes(roomRate.getRates().getRate().get(0), start, end));
        ratePlanDTO.setDescription(ratePlanMapping.getDescription());
        ratePlanDTO.setFreeMeal(translateFreeMeal(ratePlanMapping.getFreeMeal()));
        setCancelPolicy(ratePlanDTO, roomRate.getRates().getRate().get(0));
        return ratePlanDTO;
    }

    private PaymentType translatePaymentType(com.derbysoft.remote.dswitch.hotel.constants.PaymentType paymentType) {
        if (paymentType == com.derbysoft.remote.dswitch.hotel.constants.PaymentType.POA) {
            return PaymentType.POA;
        }
        if (paymentType == com.derbysoft.remote.dswitch.hotel.constants.PaymentType.PREPAY) {
            return PaymentType.PREPAY;
        }
        return PaymentType.UNKNOWN;
    }

    protected RatePlanDTO createRatePlanDTO(RatePlan ratePlanMapping, RoomRate roomRate, HotelReservationRequest request) {
        String start = request.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getStayDateRange().getCheckin();
        String end = DateTimeUtils.formatDate(DateTimeUtils.addDays(DateTimeUtils.parse(
                request.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getStayDateRange().getCheckout()), -1));

        RatePlanDTO ratePlanDTO = new RatePlanDTO();
        ratePlanDTO.setName(ratePlanMapping.getName());
        ratePlanDTO.setPaymentType(translatePaymentType(ratePlanMapping.getPaymentType()));
        ratePlanDTO.setCode(ratePlanMapping.getCode());
        ratePlanDTO.setTaxesList(translateTaxes(roomRate.getRates().getRate().get(0), start, end));
        ratePlanDTO.setDescription(ratePlanMapping.getDescription());
        ratePlanDTO.setFreeMeal(translateFreeMeal(ratePlanMapping.getFreeMeal()));
        setCancelPolicy(ratePlanDTO, roomRate.getRates().getRate().get(0));
        return ratePlanDTO;
    }

    private void setCancelPolicy(final RatePlanDTO ratePlanDTO, Rate ihgRate) {
        CancelPolicyDTO cancelPolicyDTO = convertCancelPolicy(ihgRate);
        if (cancelPolicyDTO != null) {
            ratePlanDTO.setCancelPolicy(cancelPolicyDTO);
        }else {
            CancelPolicyDTO cancelPolicy = new CancelPolicyDTO();
            CancelPenalty cancelPenalty = ihgRate.getCancelPolicies().getCancelPenalty().get(0);
            cancelPolicy.setDescription(createDesc(cancelPenalty.getPenaltyDescription()));
            ratePlanDTO.setCancelPolicy(cancelPolicy);
        }
    }

    protected CancelPolicyDTO convertCancelPolicy(Rate ihgRate) {
        if (ihgRate.getCancelPolicies() == null) {
            return null;
        }
        if (CollectionUtils.isEmpty(ihgRate.getCancelPolicies().getCancelPenalty())) {
            return null;
        }
        if (ihgRate.getCancelPolicies().getCancelPenalty().get(0).getDeadline() == null) {
            return null;
        }
        if (ihgRate.getTPAExtensions() == null) {
            return null;
        }
        CxlBasisType cxlBasisType = ihgRate.getTPAExtensions().getCxlBasisType();
        if (cxlBasisType == null) {
            return null;
        }
        if (!TranslateHelper.NO_SHOW_PENALTY.keySet().contains(cxlBasisType.getValue())) {
            logger.warn(String.format("unsupported no show penalty [%s] !!", cxlBasisType.getValue()));
            return null;
        }

        String penaltyCode = TranslateHelper.convertPenaltyCode(ihgRate);
        if (penaltyCode == null) {
            logger.warn("translate cancel policy failed : " + ihgRate.getCancelPolicies().getCancelPenalty().get(0).getDeadline());
            return null;
        }
        CancelPenalty cancelPenalty = ihgRate.getCancelPolicies().getCancelPenalty().get(0);
        CancelPolicyDTO cancelPolicyDTO = new CancelPolicyDTO();
        cancelPolicyDTO.setDescription(createDesc(cancelPenalty.getPenaltyDescription()));
        cancelPolicyDTO.setCode(penaltyCode);
        return cancelPolicyDTO;
    }

    protected String createDesc(List<Description> descriptions) {
        if (!descriptions.isEmpty()) {
            return descriptions.get(0).getText();
        }
        return BLANK;
    }

    protected List<ChargeItemDTO> translateTaxes(Rate rate, String startDate, String endDate) {
        if (rate.getFees() == null || CollectionUtils.isEmpty(rate.getFees().getFee())) {
            return new ArrayList<ChargeItemDTO>();
        }
        List<Fee> fees = rate.getFees().getFee();
        List<ChargeItemDTO> chargeItems = new ArrayList<ChargeItemDTO>();
        for (Fee fee : fees) {
            if (!fee.getType().equals(IHG_TAX_INFORMATION) && !fee.getType().equals(IHG_SERVICE_CHARGE_INFORMATION)) {
                continue;
            }
            if (fee.getPercent() != null) {
                ChargeItemDTO chargeItemDTO = new ChargeItemDTO();
                chargeItemDTO.setType(ChargeItemDTO.ChargeType.PERCENT);
                chargeItemDTO.setStartDate(startDate);
                chargeItemDTO.setEndDate(endDate);
                chargeItemDTO.setUnit(ChargeItemDTO.ChargeUnit.PER_ROOM_PER_NIGHT);
                chargeItemDTO.setValue(new BigDecimal(fee.getPercent()).divide(BigDecimal.valueOf(ONE_HUNDRED), 4, RoundingMode.HALF_UP).doubleValue());
                chargeItemDTO.setDescription(fee.getDescription().getText());
                chargeItems.add(chargeItemDTO);
            }
            if (fee.getAmount() != null) {
                ChargeItemDTO chargeItemDTO = new ChargeItemDTO();
                chargeItemDTO.setType(ChargeItemDTO.ChargeType.FIXED);
                chargeItemDTO.setUnit(ChargeItemDTO.ChargeUnit.PER_ROOM_PER_NIGHT);
                chargeItemDTO.setValue(fee.getAmount().doubleValue());
                chargeItemDTO.setStartDate(startDate);
                chargeItemDTO.setEndDate(endDate);
                chargeItemDTO.setDescription(fee.getDescription().getText());
                chargeItems.add(chargeItemDTO);
            }
        }
        return chargeItems;
    }

    private FreeMealDTO translateFreeMeal(FreeMeal freeMeal) {
        FreeMealDTO freeMealDTO = new FreeMealDTO();
        freeMealDTO.setDescription(freeMeal.getDescription());
        freeMealDTO.setType(translateFreeMealType(freeMeal.getType()));
        freeMealDTO.setQuantity(freeMeal.getQuantity());
        return freeMealDTO;
    }

    private FreeMealDTO.FreeMealType translateFreeMealType(FreeMealType type) {
        if (type == FreeMealType.BREAKFAST) {
            return FreeMealDTO.FreeMealType.BREAKFAST;
        }
        if (type == FreeMealType.BREAKFAST_AND_DINNER) {
            return FreeMealDTO.FreeMealType.BREAKFAST_AND_DINNER;
        }
        if (type == FreeMealType.BREAKFAST_AND_LUNCH_AND_DINNER) {
            return FreeMealDTO.FreeMealType.BREAKFAST_AND_LUNCH_AND_DINNER;
        }
        if (type == FreeMealType.ON_RATE) {
            return FreeMealDTO.FreeMealType.ON_RATE;
        }
        if (type == FreeMealType.UNKNOWN) {
            return FreeMealDTO.FreeMealType.NONE;
        }
        return FreeMealDTO.FreeMealType.NONE;
    }

    protected RoomTypeDTO translateRoomType(RoomType roomType, RoomRate roomRate) {
        RoomTypeDTO roomTypeDTO = new RoomTypeDTO();
        ConfigInfo configInfo = loadConfigInfo(ROOM_TYPE_NAME_FIELD);
        if (configInfo.getValue().equals(ROOM_RATE_DESCRIPTION)) {
            roomTypeDTO.setName(getRoomTypeNameByRoomRateDesc(roomType, roomRate));
        } else {
            roomTypeDTO.setName(getRoomTypeNameByAdditionalDesc(roomType, roomType.getRoomTypeCode().replace(roomRate.getRatePlanCode(), "")));
        }
        roomTypeDTO.setCode(roomType.getRoomTypeCode().replace(roomRate.getRatePlanCode(), ""));
        if (roomType.getTPAExtensions() != null) {
            roomTypeDTO.setTpaExtensions(createTpaExtensions(roomType.getTPAExtensions()));
        }
        return roomTypeDTO;
    }

    private TPAExtensionsDTO createTpaExtensions(TPAExtensions tpaExtensions) {
        TPAExtensionsDTO tpaExtensionsDTO = new TPAExtensionsDTO();
        ArrayList<KeyValue> elements = new ArrayList<KeyValue>();
        elements.add(new KeyValue(BED_TYPE_CODE, tpaExtensions.getBedTypeCode().getName()));
        tpaExtensionsDTO.setElementsList(elements);
        return tpaExtensionsDTO;
    }

    private String getRoomTypeNameByRoomRateDesc(RoomType roomType, RoomRate roomRate) {
        RoomRateDescription description = roomRate.getRoomRateDescription();
        if (description != null && !StringUtils.isBlank(description.getText())) {
            return description.getText();
        }
        return getRoomTypeNameByAdditionalDesc(roomType, roomType.getRoomTypeCode().replace(roomRate.getRatePlanCode(), ""));
    }

    private String getRoomTypeNameByAdditionalDesc(RoomType roomType, String roomTypeCode) {
        ConfigInfo configInfo = configRepository.loadUsable(ADDITIONAL_DETAIL_CODE);
        if (configInfo == null) {
            return createRoomTypeName(roomType, roomTypeCode);
        }
        if (roomType.getAdditionalDetails() != null && !roomType.getAdditionalDetails().getAdditionalDetail().isEmpty()) {
            for (AdditionalDetail additionalDetail : roomType.getAdditionalDetails().getAdditionalDetail()) {
                if (additionalDetail.getCode() != null
                        && additionalDetail.getCode().equals(configInfo.getValue())
                        && additionalDetail.getDetailDescription() != null
                        && !additionalDetail.getDetailDescription().getText().isEmpty()) {
                    return additionalDetail.getDetailDescription().getText();
                }
            }
        }
        return createRoomTypeName(roomType, roomTypeCode);
    }

    private String createRoomTypeName(RoomType roomType, String roomTypeCode) {
        if (roomType.getRoomDescription() != null && !StringUtils.isBlank(roomType.getRoomDescription().getText())) {
            return roomType.getRoomDescription().getText();
        }
        return roomTypeCode;
    }


    protected AvailRequestSegments translateAvailRequestSegments(String hotelPassport, HotelAvailRequest hotelAvailRQ) {
        AvailRequestSegment availRequestSegment = new AvailRequestSegment();
        availRequestSegment.setHotelSearchCriteria(createHotelSearchCriteria(hotelPassport));
        availRequestSegment.setStayDateRange(translateStayDateRange(hotelAvailRQ.getHotelAvailRQ().getAvailCriteria().getStayDateRange()));
        availRequestSegment.setRoomStayCandidates(createRoomStayCandidates(hotelAvailRQ));
        availRequestSegment.setRatePlanCandidates(createRatePlanCandidates(hotelAvailRQ.getHeader().getSource()));
        AvailRequestSegments availRequestSegments = new AvailRequestSegments();
        availRequestSegments.getAvailRequestSegment().add(availRequestSegment);
        return availRequestSegments;
    }

    protected AvailRequestSegments translateAvailRequestSegments(String hotelPassport, HotelReservationRequest reservationRequest) {
        AvailRequestSegment availRequestSegment = new AvailRequestSegment();
        availRequestSegment.setHotelSearchCriteria(createHotelSearchCriteria(hotelPassport));
        availRequestSegment.setStayDateRange(translateStayDateRange(reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0).getStayDateRange()));
        availRequestSegment.setRoomStayCandidates(createRoomStayCandidates(reservationRequest));
        availRequestSegment.setRatePlanCandidates(createRatePlanCandidates(reservationRequest.getHeader().getSource()));
        AvailRequestSegments availRequestSegments = new AvailRequestSegments();
        availRequestSegments.getAvailRequestSegment().add(availRequestSegment);
        return availRequestSegments;
    }

    private HotelSearchCriteria createHotelSearchCriteria(String hotelPassport) {
        HotelSearchCriteria hotelSearchCriteria = new HotelSearchCriteria();
        Criterion criterion = new Criterion();
        HotelRef hotelRef = new HotelRef();
        hotelRef.setHotelCode(loadHotel(hotelPassport).getCooperatorCode());
        criterion.setHotelRef(hotelRef);
        hotelSearchCriteria.setCriterion(criterion);
        return hotelSearchCriteria;
    }

    private RatePlanCandidates createRatePlanCandidates(String channelPassport) {
        RatePlanCandidates ratePlanCandidates = new RatePlanCandidates();
        List<RatePlan> ratePlanMappings = loadChannel(channelPassport).getRatePlans();
        if (CollectionUtil.isNotEmpty(ratePlanMappings)) {
            for (RatePlan ratePlanMapping : ratePlanMappings) {
                ratePlanCandidates.getRatePlanCandidate().add(createRatePlanCandidate(ratePlanMapping.getCode()));
            }
        }
        return ratePlanCandidates;
    }

    private RatePlanCandidate createRatePlanCandidate(String ratePlanCode) {
        RatePlanCandidate ratePlanCandidate = new RatePlanCandidate();
        ratePlanCandidate.setRatePlanCode(ratePlanCode);
        return ratePlanCandidate;
    }

    private RoomStayCandidates createRoomStayCandidates(HotelAvailRequest hotelAvailRQ) {
        RoomStayCandidates roomStayCandidates = new RoomStayCandidates();
        roomStayCandidates.getRoomStayCandidate()
                .addAll(translateRoomStayCandidates(hotelAvailRQ.getHotelAvailRQ().getAvailCriteria().getRoomStayCandidate()));
        return roomStayCandidates;
    }

    private RoomStayCandidates createRoomStayCandidates(HotelReservationRequest reservationRequest) {
        RoomStayCandidates roomStayCandidates = new RoomStayCandidates();
        roomStayCandidates.getRoomStayCandidate()
                .addAll(translateRoomStayCandidates(reservationRequest.getHotelReservationRQ().getHotelReservation().getRoomStaysList().get(0)));
        return roomStayCandidates;
    }

    private Collection<? extends RoomStayCandidate> translateRoomStayCandidates(ReservationRoomStayDTO reservationRoomStayDTO) {
        List<RoomStayCandidate> roomStayCandidates = new ArrayList<RoomStayCandidate>();
        RoomStayCandidate roomStayCandidate = new RoomStayCandidate();
        roomStayCandidate.setGuestCounts(translateGuestCounts(reservationRoomStayDTO.getAdultCount(), reservationRoomStayDTO.getChildCount()));
        roomStayCandidate.setQuantity(reservationRoomStayDTO.getNumberOfUnits());
        roomStayCandidates.add(roomStayCandidate);
        return roomStayCandidates;
    }

    private GuestCounts translateGuestCounts(Integer adult, Integer child) {
        GuestCounts result = new GuestCounts();
        List<GuestCount> counts = new ArrayList<GuestCount>();
        GuestCount adultCount = new GuestCount();
        adultCount.setAgeQualifyingCode(ADULT_QUALITY_CODE);
        adultCount.setCount(adult);
        counts.add(adultCount);

        if (child > 0) {
            GuestCount childrenCount = new GuestCount();
            childrenCount.setAgeQualifyingCode(CHILD_QUALITY_CODE);
            childrenCount.setCount(child);
            counts.add(childrenCount);
        }
        result.getGuestCount().addAll(counts);
        result.setIsPerRoom(false);
        return result;
    }

    private List<RoomStayCandidate> translateRoomStayCandidates(RoomStayCandidateDTO roomStayCandidateDTO) {
        List<RoomStayCandidate> roomStayCandidates = new ArrayList<RoomStayCandidate>();
        RoomStayCandidate roomStayCandidate = new RoomStayCandidate();
        roomStayCandidate.setGuestCounts(translateGuestCounts(roomStayCandidateDTO.getAdultCount(), roomStayCandidateDTO.getChildCount()));
        roomStayCandidate.setQuantity(roomStayCandidateDTO.getNumberOfUnits());
        roomStayCandidates.add(roomStayCandidate);
        return roomStayCandidates;
    }

    private StayDateRange translateStayDateRange(StayDateRangeDTO stayDateRange) {
        StayDateRange result = new StayDateRange();
        result.setStart(stayDateRange.getCheckin());
        result.setEnd(stayDateRange.getCheckout());
        return result;
    }

    public void setChannelAuthorizationRepository(ChannelAuthorizationRepository channelAuthorizationRepository) {
        this.channelAuthorizationRepository = channelAuthorizationRepository;
    }

    public void setRatePlanRepository(RatePlanRepository ratePlanRepository) {
        this.ratePlanRepository = ratePlanRepository;
    }

    public void setConfigRepository(ConfigRepository configRepository) {
        this.configRepository = configRepository;
    }

    public void setHotelRepository(HotelRepository hotelRepository) {
        this.hotelRepository = hotelRepository;
    }
}
